{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 面试官想从这道题中考察面试人什么？\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "在计算机编程语言中，自省（Introspection）算是一个非常重要的特性了，而 Python 作为一门动态的面向对象的语言，同样对自省有很好的支持。\n",
    "\n",
    "如果不太了解自省的，可以先看下 IBM 对于自省的解读。\n",
    "\n",
    "其实在我看来，自省就是能够在运行时确定对象的类型或属性的能力，获取它们的信息，并对它们进行操作。 有了自省，我们能够定义没有名称的函数，不按函数声明的参数顺序调用函数，甚至引用事先并不知道名称的函数。\n",
    "\n",
    "面试官的这个问题主要考察的是我们如何理解自省和自省的一些使用场景。\n",
    "\n",
    "知道一个特性很重要，但是如何使用才是重点。所以，面试官也可能要求你在回答的过程中列举一些你自己使用自省的例子。\n",
    "\n",
    "答案\n",
    "常见的自省函数有:\n",
    "\n",
    "dir()：返回与该对象关联的方法和属性的列表。\n",
    "help()：启动内置的帮助系统，查看很多 Python 自带的帮助文档信息。\n",
    "id()：返回对象的 “标识值”。\n",
    "type()：返回对象的类型。\n",
    "hasattr() 和 getattr()：分别判断对象是否有某个属性及获得某个属性值。\n",
    "callable()：如果实参是可调用的，返回 True，否则返回 False。\n",
    "isinstance()：可以确认某个对象是属于某种类型。\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 拓展"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "自省是一种在运行时确定对象类型的能力。Python 中的所有东西都是一个对象。Python 中的每个对象都可能具有属性和方法。通过使用自省，我们可以动态地检查 Python 对象。自省揭示了有关程序对象的有用信息。\n",
    "\n",
    "下面列举几个使用自省的场景：\n",
    "\n",
    "场景一：Python 交互界面\n",
    "\n",
    "有时候，我们在构思某个代码片段去解决某个特定的问题的时候，会被一些东西卡住，比如，你不知道某个对象是否支持哪些方法和属性。所以，我们一般会在交互界面上去模拟你的实现对象，并去求助于 dir() 和 help()。\n",
    "\n",
    ">>> alist=[]\n",
    ">>> dir(alist)\n",
    "['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']\n",
    "Tips: 建议大家可以安装 ipython，它比 python shell 更智能一些。比如你在想使用某个内置函数，但是你又记不清那个函数名字，ipython 可以通过 Tab 键去自动补全。\n",
    "\n",
    "好的工具可以极大地提高你的工作效率，所以我也会在分析面试问题的同时给大家介绍一些在 Python 编程中会用到的一些提高效率的办法和工具。\n",
    "\n",
    "场景二：Python 代码\n",
    "\n",
    "使用 getattr() 去获取某个对象属性。一般情况下，我们想访问某个对象的属性，一般用点属性运算符进行操作，比如一个类实例对象 obj，它有一个 name 属性，我们可以这样访问这个属性：obj.name。\n",
    "\n",
    "现在我们想要构造一个方法对同一类型的对象按照某个属性进行排序，但是具体根据那个属性由用户定义。但是我们不可能给每个属性都设计一个排序方法，这样工作量会非常大。\n",
    "\n",
    "class Person(object):\n",
    "    def __init__(self, name, age):\n",
    "        self.name = name\n",
    "        self.age = age\n",
    "    def __repr__(self):\n",
    "        # 用于显示Person对象\n",
    "        return \"Person name:{}, age: {}\".format(self.name, self.age)\n",
    "\n",
    "def persons_sort_by(persons, key):\n",
    "    # persons是一个Person对象列表\n",
    "    return sorted(persons, key=lambda p: getattr(p, key))\n",
    "\n",
    ">>> p1 = Person(name='John', age=20)\n",
    ">>> p2 = Person(name='Alex', age=24)\n",
    ">>> p3 = Person(name='Young', age=15)\n",
    ">>> persons_sort_by([p1, p2, p3], key='name')\n",
    "[Person name:Alex, age: 24,\n",
    " Person name:John, age: 20,\n",
    " Person name:Young, age: 15]\n",
    ">>> persons_sort_by([p1, p2, p3], key='age')\n",
    "[Person name:Young, age: 15,\n",
    " Person name:John, age: 20,\n",
    " Person name:Alex, age: 24]\n",
    "预览\n",
    "类似的使用在 callable() 上也适合，去判断某个对象是否是可调用对象，一般而言就是指函数。\n",
    "\n",
    "if callable(func_name):\n",
    "    res = func_name()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}